//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "CathCDDF.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdexcept>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 1000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SegmentCDDF::SegmentCDDF (): rangeStart(0),
                             rangeEnd(0),
                             length(0),
                             tmp(NULL) { }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SegmentCDDF::SegmentCDDF (const SegmentCDDF& segmentCDDF): rangeStart(segmentCDDF.rangeStart),
                                                           rangeEnd(segmentCDDF.rangeEnd),
                                                           length(segmentCDDF.length),
                                                           tmp(NULL) { }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SegmentCDDF::SegmentCDDF (const SegmentCDDF* segmentCDDF): rangeStart(segmentCDDF->rangeStart),
                                                           rangeEnd(segmentCDDF->rangeEnd),
                                                           length(segmentCDDF->length),
                                                           tmp(NULL) { }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SegmentCDDF::~SegmentCDDF () {

  if (tmp) delete tmp;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SegmentCDDF::RangeStart (int rangeStart){
 
  this->rangeStart = rangeStart;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SegmentCDDF::RangeEnd (int rangeEnd){
 
  this->rangeEnd = rangeEnd;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SegmentCDDF::Length (int length){
 
  this->length = length;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int SegmentCDDF::RangeStart (void){
  
  return this->rangeStart;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int SegmentCDDF::RangeEnd (void){
  
  return this->rangeEnd;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int SegmentCDDF::Length (void) {
  
  return this->length;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SegmentCDDF::ReadData (char* data) {

  if (!data) return false;
  
  char tmpData [strlen(data) + 1];
  strcpy(tmpData, data);
  
  char* part = strtok(tmpData, " \t\n\r");
  
  if (!part) return false;
  
  if (strstr(part, "START=")) this->rangeStart = atoi(part + 6);
  if (strstr(part, "STOP="))  this->rangeEnd   = atoi(part + 5);
  
  part = strtok(NULL, " \t\n\r");
  
  if (!part) return false;
  
  if (strstr(part, "START=")) this->rangeStart = atoi(part + 6);
  if (strstr(part, "STOP="))  this->rangeEnd   = atoi(part + 5);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SegmentCDDF::ReadData (void) {

  if (!this->tmp) return false;
  
  char tmpData [strlen(this->tmp) + 1];
  strcpy(tmpData, this->tmp);
  
  char* part = strtok(tmpData, " \t\n\r");
  
  if (!part) return false;
  
  if (strstr(part, "START=")) this->rangeStart = atoi(part + 6);
  if (strstr(part, "STOP="))  this->rangeEnd   = atoi(part + 5);
  
  part = strtok(NULL, " \t\n\r");
  
  if (!part) return false;
  
  if (strstr(part, "START=")) this->rangeStart = atoi(part + 6);
  if (strstr(part, "STOP="))  this->rangeEnd   = atoi(part + 5);
  
  if (tmp) delete tmp;
  tmp = NULL;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SegmentCDDF::ReadPair (void) {

  if (!this->tmp) return false;
  
  char tmpData [strlen(this->tmp) + 1];
  strcpy(tmpData, this->tmp);
  
  char* part = strtok(tmpData, " -");
  if (!part) return false;
  this->rangeStart = atoi(part);
  
  part = strtok(NULL, " -");
  if (!part) return false;
  this->rangeEnd = atoi(part);
  
  if (tmp) delete tmp;
  tmp = NULL;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SegmentCDDF::StoreData (char* data) {
  
  if (!data) return false;
  
  this->tmp = new char [strlen(data) + 1];
  
  strcpy(this->tmp, data);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SegmentCDDF SegmentCDDF::operator= (const SegmentCDDF& segmentCDDF) {
  
  this->rangeStart = segmentCDDF.rangeStart;
  this->rangeEnd   = segmentCDDF.rangeEnd;
  this->length     = segmentCDDF.length;
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCDDF::CathCDDF () {
  
  this->format          = new String();
  this->domain          = new String();
  this->name            = new String();
  this->source          = new String();
  this->cathCode        = new String();

  this->codeCathDomain  = NULL;
  this->domainLength    = 0;
  this->domainSequence  = new String();

  this->numberSegments  = 0;

  this->listSegments    = new TListE <SegmentCDDF> ();
  
  this->toString        = new String ();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCDDF::CathCDDF (const CathCDDF& cathCDDF) {
  
  this->format          = new String(cathCDDF.format);
  this->domain          = new String(cathCDDF.domain);
  this->name            = new String(cathCDDF.name);
  this->source          = new String(cathCDDF.source);
  this->cathCode        = new String(cathCDDF.cathCode);

  this->codeCathDomain  = cathCDDF.codeCathDomain;
  this->domainLength    = cathCDDF.domainLength;
  this->domainSequence  = new String(cathCDDF.domainSequence);

  this->numberSegments  = cathCDDF.numberSegments;

  this->listSegments    = new TListE <SegmentCDDF> (cathCDDF.listSegments);
  
  this->toString        = new String(cathCDDF.toString);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCDDF::CathCDDF (const CathCDDF* cathCDDF) {
  
  this->format          = new String(cathCDDF->format);
  this->domain          = new String(cathCDDF->domain);
  this->name            = new String(cathCDDF->name);
  this->source          = new String(cathCDDF->source);
  this->cathCode        = new String(cathCDDF->cathCode);

  this->codeCathDomain  = cathCDDF->codeCathDomain;
  this->domainLength    = cathCDDF->domainLength;
  this->domainSequence  = new String(cathCDDF->domainSequence);

  this->numberSegments  = cathCDDF->numberSegments;

  this->listSegments    = new TListE <SegmentCDDF> (cathCDDF->listSegments);
  
  this->toString        = new String(cathCDDF->toString);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCDDF::~CathCDDF () {
  
  if (this->format)         delete this->format;
  if (this->domain)         delete this->domain;
  if (this->name)           delete this->name;
  if (this->source)         delete this->source;
  if (this->cathCode)       delete this->cathCode;
  if (this->domainSequence) delete this->domainSequence;
  if (this->listSegments)   delete this->listSegments;
  if (this->toString)       delete this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::Format (String* format) {
  
  if (format) this->format->In(format);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::Domain (String* domain){
  
  if (domain) this->domain->In(domain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::Name (String* name){
  
  if (name) this->name->In(name);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::Source (String* source){
  
  if (source) this->source->In(source);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::CathCode (String* cathCode){
  
  if (cathCode) this->cathCode->In(cathCode);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::CodeCathDomain (CathCLF* codeCathDomain){
 
  this->codeCathDomain = codeCathDomain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::DomainLength (int domainLength){
 
  this->domainLength = domainLength;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::DomainSequence (String* domainSequence){
  
  if (domainSequence) this->domainSequence->In(domainSequence);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::NumberSegments (int numberSegments){
 
  this->numberSegments = numberSegments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::ListSegments (TListE <SegmentCDDF>* listSegments){
  
  if (listSegments) *(this->listSegments) = *(listSegments);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::Format (void){
 
  return this->format;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::Domain (void){
  
  return this->domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::Name (void){
  
  return this->name;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::Source (void){
  
  return this->source;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::CathCode (void){
  
  return this->cathCode;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCLF* CathCDDF::CodeCathDomain (void){
  
  return this->codeCathDomain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int CathCDDF::DomainLength (void){
  
  return this->domainLength;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::DomainSequence (void){
  
  return this->domainSequence;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int CathCDDF::NumberSegments (void){
  
  return this->numberSegments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <SegmentCDDF>* CathCDDF::ListSegments (void) {
  
  return this->listSegments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool CathCDDF::ReadFromString (String* data) {
  
  if (!data || !data->Length()) return false;
  
  this->CleanData();
  
  char  tmpData [data->Length() + 1];
  char* lines             = NULL;
  
  int   lastSegmentRange  = 0;
  int   lastSegmentLength = 0;
  
  strcpy(tmpData, data->Out());
  tmpData[data->Length()] = '\0';

  lines = strtok(tmpData, "\n");
  
  while (lines) {
    
    if      (!strncmp(lines, "FORMAT",    strlen("FORMAT"))) {
      this->format->Add(lines + 10); 
      this->format->Trim();
    }
    else if (!strncmp(lines, "DOMAIN",    strlen("DOMAIN"))) {
      this->domain->Add(lines + 10); 
      this->domain->Trim();
    }
    else if (!strncmp(lines, "NAME",      strlen("NAME"))) {
      this->name->Add(lines + 10); 
    }
    else if (!strncmp(lines, "SOURCE",    strlen("SOURCE"))) {
      this->source->Add(lines + 10); 
    }
    else if (!strncmp(lines, "CATHCODE",  strlen("CATHCODE"))) {
      this->cathCode->Add(lines + 10); 
      this->cathCode->Trim();
    }
    else if (!strncmp(lines, "DLENGTH",   strlen("DLENGTH"))) {
      this->domainLength = atoi(lines + 10); 
    }
    else if (!strncmp(lines, "DSEQS",     strlen("DSEQS"))) {
      this->domainSequence->Add(lines + 10); 
    }
    else if (!strncmp(lines, "NSEGMENTS", strlen("NSEGMENTS"))) {
      this->numberSegments = atoi(lines + 10); 
      for (int i = 0; i < this->numberSegments; i++)
        this->listSegments->Add(new SegmentCDDF ());
    }
    else if (!strncmp(lines, "SRANGE",    strlen("SRANGE"))) {
      this->listSegments->Get(lastSegmentRange++)->StoreData(lines + 10);
    }
    else if (!strncmp(lines, "SLENGTH",   strlen("SLENGTH"))) {
      this->listSegments->Get(lastSegmentLength++)->Length(atoi(lines + 10));
    }
    
    lines = strtok(NULL, "\n");
    
  }
  
  for (int i = 0; i < this->numberSegments; i++)
    this->listSegments->Get(i)->ReadData();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool  CathCDDF::ReadFromString (char* data) {
  
  if (!data) return false;
  
  String dataChar;
  dataChar.In(data);
  
  return this->ReadFromString(&dataChar);    
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void CathCDDF::CleanData (void) {
  
  this->format->In("");
  this->domain->In("");
  this->name->In("");
  this->source->In("");
  this->cathCode->In("");
  
  this->domainLength   = 0;;
  this->domainSequence->In("");
  
  this->numberSegments = 0;

  this->listSegments->Clear();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* CathCDDF::ToStringSegment (void) {
  
  this->toString->In("");
  
  char buffer [LENGTHTEXT + 1];
  bool first = true;
  
  buffer[0] = '\0';
  
  this->listSegments->SetInitial();
  
  while (this->listSegments->SetNext()) {
    
    SegmentCDDF* currentSegment = this->listSegments->GetCurrent();
    
    sprintf (buffer, (first)?"%s%d-%d\0":"%s;%d-%d\0",  buffer, currentSegment->RangeStart(), currentSegment->RangeEnd());
    
    first = false;
    
  }
  
  this->toString->In(buffer);
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
CathCDDF CathCDDF::operator= (const CathCDDF& cathCDDF) {
  
  this->format->In(cathCDDF.format);
  this->domain->In(cathCDDF.domain);
  this->name->In(cathCDDF.name);
  this->source->In(cathCDDF.source);
  this->cathCode->In(cathCDDF.cathCode);

  this->domainLength    = cathCDDF.domainLength; 
  this->domainSequence->In(cathCDDF.domainSequence);

  this->numberSegments  = cathCDDF.numberSegments;

  *(this->listSegments) = *(cathCDDF.listSegments);
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
